var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
define(["require", "exports", "http", "url", "querystring", "./settings", "mysql"], function (require, exports, http, url, querystring, settings, mysql) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    const errors = {
        searchCanntNull: () => new Error('Search can not be null.'),
        parameterRequired: (name) => new Error(`Parameter '${name}' is required.`),
        objectNotExists: (typeName, name) => new Error(`Object ${typeName} '${name}' is not exists.`),
        dataFormatError: () => new Error('Data format error.'),
        pathNotSupport: (path) => new Error(`Path '${path}' is not supported.`),
        actionResultIsNull: () => new Error("Action result can not be null."),
    };
    const contentTypes = {
        application_json: 'application/json',
        text_plain: 'text/plain',
    };
    const hostname = 'localhost';
    const port = 3228;
    const server = http.createServer((req, res) => __awaiter(this, void 0, void 0, function* () {
        try {
            let urlInfo = url.parse(req.url);
            let path = urlInfo.pathname;
            let result;
            let arr = path.split('/').filter(o => o);
            switch (arr[0]) {
                case 'upload':
                    result = yield upload(req, res);
                    break;
                case 'get':
                    if (arr.length != 2)
                        throw errors.pathNotSupport(path);
                    if (/^\/[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$/i.test(arr[1])) {
                        let id = path.substr(1);
                        result = yield load(req, res, { id });
                    }
                    else {
                        let name = arr[1];
                        result = yield load(req, res, { name });
                    }
                    break;
                default:
                    throw errors.pathNotSupport(path);
            }
            if (!result)
                throw errors.actionResultIsNull();
            res.setHeader("content-type", result.contentType || contentTypes.text_plain);
            res.statusCode = result.statusCode || 200;
            res.end(result.data);
        }
        catch (e) {
            let err = e;
            res.setHeader('content-type', contentTypes.application_json);
            res.statusCode = 600;
            let { name, stack } = err;
            var text = JSON.stringify({ name, stack });
            res.write(text);
            res.end();
        }
    }));
    server.listen(port, () => {
        console.log(`server running at http://${hostname}:${port}`);
    });
    function load(req, res, args) {
        return __awaiter(this, void 0, void 0, function* () {
            args = args || {};
            if (args.id == null && args.name == null)
                throw errors.parameterRequired('name or id');
            return new Promise((resolve, reject) => {
                let conn = mysql.createConnection(settings.mysql_image_setting);
                let field = args.id ? 'id' : 'name';
                let sql = `select id, data, type from file where ${field} = ?`;
                conn.query(sql, args.id || args.name, (err, rows, fields) => {
                    if (err) {
                        reject(err);
                        return;
                    }
                    if (!rows[0]) {
                        let err = errors.objectNotExists('file', args.id || args.name);
                        reject(err);
                        return;
                    }
                    let arr = (rows[0].data || '').split(',');
                    if (arr.length != 2) {
                        reject(errors.dataFormatError());
                        return;
                    }
                    let buffer = new Buffer(arr[1], 'base64');
                    resolve({ data: buffer, contentType: rows[0].type });
                    return;
                });
                conn.end();
            });
        });
    }
    function upload(req, res) {
        return __awaiter(this, void 0, void 0, function* () {
            //image
            let obj = yield parsePostData(req);
            let { file, name } = obj;
            if (file == null) {
                throw errors.parameterRequired("file");
            }
            let application_id = req.headers['application-id'] || parseQueryString(req)['application'];
            if (application_id == null)
                throw errors.parameterRequired('application-id');
            return new Promise((resolve, reject) => {
                let create_date_time = new Date(Date.now());
                let conn = mysql.createConnection(settings.mysql_image_setting);
                let sql = `insert into file set ?`;
                let item = { id: guid(), data: file, create_date_time, application_id, name };
                conn.query(sql, item, (err, rows, fields) => {
                    if (err) {
                        reject(err);
                        return;
                    }
                    let result = {
                        data: JSON.stringify({ id: item.id }),
                        contentType: contentTypes.application_json
                    };
                    resolve(result);
                });
                conn.end();
            });
        });
    }
    function parseQueryString(req) {
        let urlInfo = url.parse(req.url);
        let { search } = urlInfo;
        let contentType = req.headers['content-type'] || '';
        if (!search)
            return {};
        search = search[0] == '?' ? search.substr(1) : search;
        let result;
        if (contentType.indexOf('application/json') >= 0) {
            result = JSON.parse(search);
        }
        else {
            result = querystring.parse(search);
        }
        return result;
    }
    function parsePostData(request) {
        let method = (request.method || '').toLowerCase();
        let length = request.headers['content-length'] || 0;
        let contentType = request.headers['content-type'];
        if (length <= 0)
            return Promise.resolve({});
        return new Promise((reslove, reject) => {
            var text = "";
            request.on('data', (data) => {
                text = text + data.toString();
            });
            request.on('end', () => {
                let obj;
                try {
                    if (contentType.indexOf('application/json') >= 0) {
                        obj = JSON.parse(text);
                    }
                    else {
                        obj = querystring.parse(text);
                    }
                    reslove(obj);
                }
                catch (err) {
                    reject(err);
                }
            });
        });
    }
    function guid() {
        function s4() {
            return Math.floor((1 + Math.random()) * 0x10000)
                .toString(16)
                .substring(1);
        }
        return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
            s4() + '-' + s4() + s4() + s4();
    }
});
